package m.appserver;

import com.alibaba.fastjson.JSONObject;
import io.netty.handler.codec.http.HttpMethod;
import m.common.action.*;
import m.system.db.TransactionManager;
import m.system.util.ActionUtil;
import m.system.util.ClassUtil;
import m.system.util.JSONMessage;
import m.system.util.StringUtil;

import java.lang.reflect.Method;

public class ActionRedirect implements ServerResult {
    /**
     * uriMethod  uri方法
     * action action类
     * method 执行action方法
     */
    public ActionRedirect(HttpMethod uriMethod,Class<? extends Action> action,String method){
        this.uriMethod=uriMethod;
        this.action=action;
        this.method=method;
        this.json=null;
    }
    /**
     * uriMethod  uri方法
     * action action类
     * method 执行action方法
     * json 附加参数
     */
    public ActionRedirect(HttpMethod uriMethod,Class<? extends Action> action,String method,JSONObject json){
        this.uriMethod=uriMethod;
        this.action=action;
        this.method=method;
        this.json=json;
    }
    /** 默认GET
     * action action类
     * method 执行action方法
     */
    public ActionRedirect(Class<? extends Action> action,String method){
        this(HttpMethod.GET,action,method);
    }
    /** 默认POST
     * action action类
     * method 执行action方法
     * json 附加参数
     */
    public ActionRedirect(Class<? extends Action> action,String method,JSONObject json){
        this(HttpMethod.POST,action,method,json);
    }
    /** 默认POST
     * action action类
     * method 执行action方法
     * json 附加参数
     */
    public ActionRedirect(Class<? extends Action> action, String method, JSONMessage json){
        this(HttpMethod.POST,action,method,json.toJSON());
    }
    /**
     * uriMethod  uri方法
     * action action类
     * method 执行action方法
     * json 附加参数
     */
    public ActionRedirect(HttpMethod uriMethod,Class<? extends Action> action,String method,JSONMessage json){
        this(uriMethod,action,method,json.toJSON());
    }

    /**
     * vueResult  VueResult
     */
    public ActionRedirect(VueResult vueResult){
        this.vueResult=vueResult;
    }
    /**
     * htmlResult  htmlResult
     */
    public ActionRedirect(HtmlResult htmlResult){
        this.htmlResult=htmlResult;
    }
    private HttpMethod uriMethod;
    private Class<? extends Action> action;
    private Action realAction;
    private String method;
    private JSONObject json;
    private VueResult vueResult;
    private HtmlResult htmlResult;
    private Class<?>[] params;
    protected Object toResult(RequestUtil reqUtil,ResponseUtil resUtil) throws Exception {
        //VueResult 构造的直接返回
        if(null!=this.vueResult) return this.vueResult;
        //htmlResult 构造的直接返回
        if(null!=this.htmlResult) return this.htmlResult;
        //其他构造
        if (null != this.json)
            ActionUtil.fillJSONObject(reqUtil.getRequestJson(), this.json);
        realAction = reqUtil.getRequestJson().toJavaObject(this.action);
        realAction.setRequest(reqUtil);
        realAction.setResponse(resUtil);
        realAction.setAuthorization(reqUtil.getHeader("Authorization"));
        //查找action定义的请求注解,并返回参数名称和类型map
        RequestParam rp = ActionUtil.getRequestParamList(realAction.getClass(), this.method, this.uriMethod.name());
        this.params=rp.getParamList().values().toArray(new Class<?>[]{});
        realAction.setFileMap(reqUtil.getFiles());
        //记录日志
        if(StringUtil.notSpace(rp.getLogTitle()))
            realAction.log(rp.getLogTitle(),rp.getLogDescription());
        //执行action的方法-----------------------------------
        realAction.beforeExecute();//action方法执行之前执行
        Object r;
        try {
            if (rp.isTransaction()) {
                TransactionManager tm = new TransactionManager();
                try {
                    tm.begin();
                    r = ClassUtil.executeMethod(realAction, this.method, params, resUtil.toMethodParams(rp.getParamList(), reqUtil.getRequestJson()));
                    tm.commit();
                    return r;
                } catch (Exception e) {
                    tm.rollback();
                    throw e;
                }
            } else {
                r = ClassUtil.executeMethod(realAction, this.method, params, resUtil.toMethodParams(rp.getParamList(), reqUtil.getRequestJson()));
            }
            realAction.afterExecute(r);//action方法执行之后执行
        }catch (Exception e){
            r=realAction.exceptionExecute(e,toResultType());//action方法执行报错后执行
        }
        return r;
    }
    protected ActionResultType toResultType(){
        if(null!=this.vueResult) return ActionResultType.VuePage;
        if(null!=this.htmlResult) return ActionResultType.HtmlPage;
        Method m=ClassUtil.getDeclaredMethods(this.action,this.method,this.params);
        if(null!=m) {
            return ActionResultType.to(m.getAnnotatedReturnType().getType());
        }
        return null;
    }
    protected Action getRealAction(){
        return realAction;
    }

    @Override
    public String toString() {
        if(null!=this.vueResult) return this.vueResult.toHtmlString();
        if(null!=this.htmlResult) return this.htmlResult.toHtmlString();
        else return this.action.getName()+"."+this.method;
    }
    private ServerResultStatus status=ServerResultStatus.SUCCESS;
    public ActionRedirect setStatus(ServerResultStatus status) {
        this.status = status;
        return this;
    }

    @Override
    public ServerResultStatus getStatus() {
        return this.status;
    }

    @Override
    public String getContent() {
        if(null!=this.vueResult) return this.vueResult.getContent();
        if(null!=this.htmlResult) return this.htmlResult.getContent();
        else return this.action.getName()+"."+this.method;
    }
}
